﻿using System;
using Microsoft.SPOT;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Presentation.Media;

namespace LEDONET.EasyDisplay
{
    public enum Orientation : byte
    {
        Portrait = 0,
        Landscape
    }

    public class EasyDisplay
    {
        private const ushort SCREEN_WIDTH = 480;
        private const ushort SCREEN_HEIGHT = 272;

        private static Orientation CurrentOrientation;
        private static ushort Width;
        private static ushort Height;

        public static void Initialize(Orientation screen)
        {
            Width = SCREEN_WIDTH;
            Height = SCREEN_HEIGHT;
            CurrentOrientation = screen;

            // call native code
            EasyDisplay.InitializeDisplay(screen);
        }

        /// <summary>
        /// The width of the display.
        /// </summary>
        /// <returns>The current width.</returns>
        public static ushort GetWidth()
        {
            return EasyDisplay.Width;
        }

        /// <summary>
        /// The height of the display.
        /// </summary>
        /// <returns>The current height.</returns>
        public static ushort GetHeight()
        {
            return EasyDisplay.Height;
        }

        public static void Circle(int x, int y, int radius, Color foreColor, bool fill = false)
        {
            uint rgb = Get565RGBColor(foreColor);
            EasyDisplay.DrawCircle((ushort)x, (ushort)y, (ushort)radius, (ushort)rgb, fill);
        }

        public static void Draw(string text, int x, int y, Font font, Color foreColor, Color backColor)
        {
            int width = 0;
            for (int i = 0; i < text.Length; i++)
            {
                width += font.CharWidth((char)(text[i]));
            }

            Bitmap bmp = new Bitmap(width, font.Height);
            bmp.DrawRectangle(backColor, 100, 0, 0, width, font.Height, 0, 0, backColor, 0, 0, backColor, 0, 0, 0);
            bmp.DrawText(text, font, foreColor, 0, 0);
            
            Draw(new TinyBitmap(bmp), x, y);
        }

        public static void Draw(TinyBitmap tb, int xDst, int yDst)
        {
            Draw(tb, xDst, yDst, 0, 0, tb.Width, tb.Height);
        }

        public static void Draw(TinyBitmap tb, int xDst, int yDst, int xSrc, int ySrc, uint width, uint height)
        {
            EasyDisplay.DrawImage(tb.Data, (ushort)xDst, (ushort)yDst, (ushort)tb.Width, (ushort)tb.Height, (ushort)xSrc, (ushort)ySrc, (ushort)width, (ushort)height);
        }

        public static void DrawText(string text, int xDst, int yDst, Color color)
        {
            uint rgb = Get565RGBColor(color);
            EasyDisplay.DrawText(text, (ushort)text.Length, (ushort) xDst, (ushort) yDst, rgb);
        }

        public static void DrawRectangle(int xStart, int yStart, int Width, int Height, Color color, bool fill = false)
        {
            uint rgb = Get565RGBColor(color);
            EasyDisplay.DrawRect((ushort)xStart, (ushort)yStart, (ushort)Width, (ushort)Height, (ushort)rgb, fill);
        }

        public static void ClearDisplay(Color color = Color.Black)
        {
            uint rgbcolor = Get565RGBColor(color);
            EasyDisplay.ClearDisplay(rgbcolor);
        }

        // utility to get 565 RGB color
        static uint Get565RGBColor(Color color)
        {
            uint rgbcolor = 0;
            int r = ColorUtility.GetRValue(color) >> 2;
            int g = ColorUtility.GetGValue(color) >> 1;
            int b = ColorUtility.GetBValue(color) >> 2;
            rgbcolor = (uint) ((r << 11) | (g << 4) | b);
            return rgbcolor;
        }

        public static void ScrollDisplay(int x, int y, int width, int height, int scroll_x, int scroll_y, bool up_down)
        {
            
            byte h_data = (byte)((( y + height) & 0xff00) >> 8);
            byte l_data = (byte)(( y + height) & 0xff);
            //ScrollArea(x, y, width, height, scroll_x, scroll_y, up_down);
            WriteCommand(0x37); // set scroll area start
            WriteData(h_data);
            WriteData(l_data);
        }

        public static void SetPWMBacklight(byte value)
        {
            WriteCommand(0xBE); // set PWM register
            WriteData(0x06);
            WriteData(value);
            WriteData(0x01);
            WriteData(0xFF);
            WriteData(0x00);
            WriteData(0x01);

        }

        public static void DrawSingleLine(int x0, int y0, int x1, int y1, Color color, int thickness )
        {
            uint rgbcolor = Get565RGBColor(color);
            DrawLine((ushort)x0, (ushort)y0, (ushort)x1, (ushort) y1, (ushort)rgbcolor,(ushort) thickness);
        }

        // Native code calls
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean InitializeDisplay(Orientation screenmode);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean WriteCommand(ushort cmd);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean WriteData(ushort data);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean DrawRect(ushort x, ushort y, ushort width, ushort height, ushort color, bool fill);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean DrawLine(ushort x0, ushort y0, ushort x1, ushort y1, ushort color, ushort thickness);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean DrawCircle(ushort x, ushort y, ushort radius, ushort color, bool fill);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean DrawImage(byte[] image, ushort xDst, ushort yDst, ushort originalWidth, ushort originalHeight, ushort xSrc, ushort ySrc, ushort width, ushort height);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean DrawText(string text, ushort textlen, ushort xDst, ushort yDst, uint color);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean ClearDisplay(uint color);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean ScrollArea(ushort x, ushort y, ushort width, ushort height, ushort scrollx, ushort scrolly, bool up_down);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern private static Boolean SetPixel(ushort x, ushort y, ushort color);


    }
}
